package br.cnpq.webflowah.ontologia;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.mindswap.owl.OWLIndividual;
import org.mindswap.owl.OWLKnowledgeBase;
import org.mindswap.owl.OWLOntology;
import org.mindswap.owls.generic.expression.Expression;
import org.mindswap.owls.process.Condition;
import org.mindswap.owls.process.Input;
import org.mindswap.owls.process.Output;
import org.mindswap.owls.process.Result;
import org.mindswap.owls.service.Service;

import com.hp.hpl.jena.ontology.OntModel;

public class DocumentoOWLS implements Serializable {

	private static final long serialVersionUID = 1L;
			
	private OWLOntology ontology = null;
	
	private DocumentoOWLS(OWLOntology ont) {
		this.ontology = ont;
	}
		
	public List getOntologies() {
		List<OWLOntology> list = null;

		Iterator iter = ontology.getKB().getOntologies().iterator();
		while (iter.hasNext()) {
			OWLOntology ont = (OWLOntology) iter.next();

			if (!ont.equals(ontology.getKB().getBaseOntology())) {
				if (list == null) list = new ArrayList<OWLOntology>();
				list.add(ont);
			}
		}
		
		return list;
	}
	
	public List getServices() {
		List list = ontology.getServices();
		// Correcao devido ao metodo getServices retornar uma lista duplicada
		if (list != null) list = list.subList(0, list.size()/2);
		return list;
	}
	
	public Object getService() {
		return ontology.getService();
	}
	
	public List getInputs(Object arg) {
//		List<String> list = null;
		List<String> list = new ArrayList<String>();
		OWLIndividual ind = (OWLIndividual) arg;
		Service service = ind != null ? (Service) ind.castTo(Service.class) : null;

		if (service != null) {
			Iterator iter = service.getProfile().getInputs().iterator();
			while (iter.hasNext()) {
//				if (list == null) list = new ArrayList<String>();
				Input input = (Input) iter.next(); 
				list.add(input.getLocalName());
			}
		}
		
		return list;
	}
	
	public List getOutputs(Object arg) {
//		List<String> list = null;
		List<String> list = new ArrayList<String>();
		OWLIndividual ind = (OWLIndividual) arg;
		Service service = ind != null ? (Service) ind.castTo(Service.class) : null;

		if (service != null) {
			Iterator iter = service.getProfile().getOutputs().iterator();
			while (iter.hasNext()) {
//				if (list == null) list = new ArrayList<String>();
				Output output = (Output) iter.next(); 
				list.add(output.getLocalName());
			}
		}
		
		return list;
	}
	
	public List getPreConditions(Object arg) {
//		List<String> list = null;
		List<String> list = new ArrayList<String>();
		OWLIndividual ind = (OWLIndividual) arg;
		Service service = ind != null ? (Service) ind.castTo(Service.class) : null;

		if (service != null) {
			Iterator iter = service.getProfile().getConditions().iterator();
			while (iter.hasNext()) {
//				if (list == null) list = new ArrayList<String>();
				Condition condition = (Condition) iter.next();
				if (condition.getLocalName() != null)				
					list.add(condition.getLocalName());
			}
		}
		
		return list;
	}
	
	public List getResults(Object arg) {
		List<String> list = new ArrayList<String>();
		OWLIndividual ind = (OWLIndividual) arg;
		Service service = ind != null ? (Service) ind.castTo(Service.class) : null;

		if (service != null) {
			Iterator iter0 = service.getProfile().getResults().iterator();
			while (iter0.hasNext()) {
//				if (list == null) list = new ArrayList<String>();
				Result result = (Result) iter0.next();
				if (result.getLocalName() != null)				
					list.add(result.getLocalName());
			}
		}		
		
		return list;
	}
	
	public List getEffects(Object arg) {
//		List<String> list = null;
		List<String> list = new ArrayList<String>();
		OWLIndividual ind = (OWLIndividual) arg;
		Service service = ind != null ? (Service) ind.castTo(Service.class) : null;

		if (service != null) {
			Iterator iter0 = service.getProfile().getResults().iterator();
			while (iter0.hasNext()) {
//				if (list == null) list = new ArrayList<String>();
				Result result = (Result) iter0.next();
				Iterator iter1 = result.getEffects().iterator();
				while (iter1.hasNext()) {
					Expression effect = (Expression) iter1.next();
					if (effect.getLocalName() != null)
						list.add(effect.getLocalName());
				}
			}
		}
		
		return list;		
	}
	
	public String getDescription(Object arg) {
		OWLIndividual ind = (OWLIndividual) arg;
		Service service = ind != null ? (Service) ind.castTo(Service.class) : null;
		return (service != null && service.getProfile() != null) ? 
				service.getProfile().getTextDescription() : "";		
	}
		
	private static void carregarImports(OntModel model, OWLKnowledgeBase kb, 
			List<String> list, String path) {
		Iterator iter = model.listImportedOntologyURIs().iterator();
		while (iter.hasNext()) {
			String uri = iter.next().toString();
			if (uri.endsWith("#")) uri = uri.substring(0, uri.lastIndexOf("#"));
			if (list.contains(uri)) continue;			
			list.add(uri);
			String filename = uri.substring(uri.lastIndexOf('/')+1, uri.length());
			if (!filename.endsWith(".owl")) filename += ".owl";
			OWLOntology ontImport = kb.createOntology(URI.create(uri));
			model = (OntModel) ontImport.getImplementation();
			File file = new File(path + filename);
			if (file.exists()) {
				OntModel modelImport = (OntModel) model.read(file.toURI().toString());
				carregarImports(modelImport, kb, list, path);
			}
		}		
	}
	
	public static DocumentoOWLS obterOntologia(String arg, boolean local) {
		try {
			OWLKnowledgeBase kb = Repositorio.newInstance(false);			
			OWLOntology ont = null;
			
			if (local) { //obter de um arquivo local
				File file = new File(arg);
				String path = file.getAbsolutePath();
				path = path.substring(0, path.lastIndexOf('\\')+1);
				ont = kb.createOntology();
				OntModel model = (OntModel) ont.getImplementation();
				model.read(file.toURI().toString());
				
				Iterator iter = model.listOntologies();
				if (iter.hasNext()) {
					String uri = iter.next().toString();
					ont.setURI(URI.create(uri));
				}
				
				carregarImports(model, kb, new ArrayList<String>(), path);
			} else { //obter de uma URL
				ont = kb.read(arg);
			}

			return new DocumentoOWLS(ont); 
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();			
		}
		return null;
	}
		
	public static void salvarOntologia(DocumentoOWLS arg) {
		try { 
			OWLKnowledgeBase kb = Repositorio.getInstance();

			Iterator iter = arg.getOntologies().iterator();
			while (iter.hasNext()) {
				OWLOntology ont = (OWLOntology) iter.next();
				String filename = ont.getURI().toString();
				filename = filename.substring(filename.lastIndexOf('/'), filename.length());
				if (!filename.endsWith(".owl")) filename += ".owl";				
				File file = new File(kb.getReader().getCache().getLocalCacheDirectory() + filename);

				if (!file.exists()) // armazena no service.idx
					kb.getReader().getCache().addCachedFile(ont.getURI().toString(), file);

				FileOutputStream fos = new FileOutputStream(file);
				ont.write(fos);
				fos.close();
			}

			kb.getReader().getCache().updateIndexFile();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
		
}
